/*
    rpc调用客户端业务层：
        功能：给用户提供三种rpc调用方法，这三种方法的实现是通过requestor模块中的三种发送请求的方法实现的，区别就是这三种方法的参数更加具象化
        设计原因：居然rpc调用器和requestor模块很相似为什么还要抽离出来？
                解耦的思想，为了让rpc调用器更专注与提供业务服务，而不是解决对请求与响应的时序问题，这样一来rpc调用器变得精简而不繁重，
                并且后面请求与响应管理需要调整，我只需要修改requestor模块，而上层业务代码几乎不动
*/

#pragma once
#include "requestor.hpp"
#include "../common/uuid.hpp"

namespace ns_jsonrpc
{
    namespace ns_client
    {
        class RpcCaller
        {
        public:
            using RpcCallerPtr = std::shared_ptr<RpcCaller>;
            using JsonAsyncResponse = std::future<Json::Value>;
            using JsonResponseCallBack = std::function<void(const Json::Value &)>;

        public:
            RpcCaller(const Requestor::RequestorPtr& requestor) : _requestor(requestor)
            {
            }

            // 同步请求
            bool call(const BaseConnection::BaseConnectionPtr &conn, const std::string &method, const Json::Value &params, Json::Value &result)
            {
                // 1.组织rpc请求消息
                RpcRequest::RpcRequestPtr req = MessageFactory::create<RpcRequest>();
                req->setId(UUID::uuid());
                req->setMType(MType::REQ_RPC);
                req->setMethod(method);
                req->setParams(params);

                // 2.发送请求并获取响应
                BaseMessage::BaseMessagePtr rsp;
                _requestor->send(conn, req, rsp);

                // 3.处理响应
                RpcResponse::RpcResponsePtr rpcRsp = std::dynamic_pointer_cast<RpcResponse>(rsp);
                if (rpcRsp == nullptr || !rpcRsp->check()) // body检查
                {
                    LOG_ERROR("sync call failed, invalid response\n");
                    return false;
                }
                if (rpcRsp->rcode() != RCode::RCODE_OK)
                {
                    LOG_ERROR("sync call failed, error reason: %s\n", errReason(rpcRsp->rcode()).c_str());
                    return false;
                }
                result = rpcRsp->result();
                return true;
            }

            // 异步请求
            bool call(const BaseConnection::BaseConnectionPtr &conn, const std::string &method, const Json::Value &params, JsonAsyncResponse &result)
            {
                // 1.组织rpc请求消息
                RpcRequest::RpcRequestPtr req = MessageFactory::create<RpcRequest>();
                req->setId(UUID::uuid());
                req->setMType(MType::REQ_RPC);
                req->setMethod(method);
                req->setParams(params);

                // 2.发送请求并获取响应
                // 这里采用异步回调的方式处理异步请求
                // 注意：这里不能使用局部变量，因为返回了关联future，当此函数调用完，局部对象释放，外部使用future会出现问题
                std::shared_ptr<std::promise<Json::Value>> jsonPromise = std::make_shared<std::promise<Json::Value>>();
                result = jsonPromise->get_future();
                Requestor::ResponseCallback callback = std::bind(&RpcCaller::asyncCallback, this, jsonPromise, std::placeholders::_1);
                _requestor->send(conn, req, callback);
                return true;
            }

            // 回调请求
            bool call(const BaseConnection::BaseConnectionPtr &conn, const std::string &method, const Json::Value &params, const JsonResponseCallBack &callback)
            {
                // 1.组织rpc请求消息
                RpcRequest::RpcRequestPtr req = MessageFactory::create<RpcRequest>();
                req->setId(UUID::uuid());
                req->setMType(MType::REQ_RPC);
                req->setMethod(method);
                req->setParams(params);

                // 2.发送请求
                Requestor::ResponseCallback cb = std::bind(&RpcCaller::Callback, this, callback, std::placeholders::_1);
                _requestor->send(conn, req, cb);
                return true;
            }

        private:
            // 异步回调
            // （当接收到消息的时候，消息会被传送到requestor模块的onResponse方法中处理，而此函数就是在onResponse方法中，如果请求类型是回调类型的时候，所调用的回调函数）
            // （因为在RpcCaller模块中要异步获取到消息正文结果(Json::Value)，只能通过接收到消息时，将消息正文设置给promise对象，外部通过关联的future对象来获取结果）
            void asyncCallback(std::shared_ptr<std::promise<Json::Value>> asyncRsp, const BaseMessage::BaseMessagePtr &msg)
            {
                // 1.处理响应
                RpcResponse::RpcResponsePtr rpcRsp = std::dynamic_pointer_cast<RpcResponse>(msg); // 转换为具体响应类型
                if (rpcRsp == nullptr || !rpcRsp->check()) // body检查
                {
                    LOG_ERROR("async call failed, invalid response\n");
                    return;
                }

                if (rpcRsp->rcode() != RCode::RCODE_OK)
                {
                    LOG_ERROR("async call failed, error reason: %s\n", errReason(rpcRsp->rcode()).c_str());
                    return;
                }

                // 3.获取响应正文
                asyncRsp->set_value(rpcRsp->result());
            }

            // 回调（当接受到消息时，调用用户提前设置好的回调来处理）
            void Callback(const JsonResponseCallBack &callback, const BaseMessage::BaseMessagePtr &msg)
            {
                // 1.处理响应
                RpcResponse::RpcResponsePtr rpcRsp = std::dynamic_pointer_cast<RpcResponse>(msg);
                if (rpcRsp == nullptr || !rpcRsp->check()) // body检查
                {
                    LOG_ERROR("callback failed, invalid response\n");
                    return;
                }
                if (rpcRsp->rcode() != RCode::RCODE_OK)
                {
                    LOG_ERROR("callback failed, error reason: %s\n", errReason(rpcRsp->rcode()).c_str());
                    return;
                }

                // 2.调用回调处理
                callback(rpcRsp->result());
            }

        private:
            Requestor::RequestorPtr _requestor;
        };
    }
}